home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 201-220 / scopedisk211 / climax / purify.a < prev    next >
Encoding:
Text File  |  1995-03-20  |  9.1 KB  |  252 lines

  1. * This here is startup code for Amiga Aztec C programs, to make them pure.
  2. * Assemble it with the command "as purify.a" and link the resulting purify.o
  3. * file with your C program, in some manner like "ln yourprogram.o purify.o -lc",
  4. * and your program can then be marked as pure, and made resident, IF it meets
  5. * certain conditions:
  6. * 1) You must not use the large data model for accessing your global varialbes.
  7. * 2) You MUST NOT call the geta4() function from within any part of your program
  8. * that is run outside of your main process.  Subtasks, interrupt handlers, and
  9. * wedges installed with SetFunction may not use geta4, and thus may not access
  10. * your global variables by any direct method.
  11. * 3) You must not initialize global variables using the addresses of other
  12. * global variables.  For example, the following is not correct:
  13. *     char foo[100], bar[100];
  14. *     char *foobar[2] = { foo, bar };        /* WRONG */
  15. * If you do this, then any references to foobar[0] will end up accessing
  16. * DIFFERENT MEMORY than accessing foo directly will.  Instead, you have to do
  17. * such initialization in the code, with statements like "foobar[0] = foo;
  18. * foobar[1] = bar;".
  19. *
  20. * 4) You must not use detach.o; this applies to ALL pure programs, not just
  21. * those that use this startup code.
  22. * 5) Do not use this when making a shared library or device driver.  ("Duh...")
  23. * This was originally based on resident.asm by Olaf Barthel, which is available
  24. * on fish disk 396, but does not presently contain any of his code.  Barthel's
  25. * version had serious errors in it, and will not work in many cases.  It was
  26. * also a lot less efficient than the method I use.
  27. *
  28. * With the Aztec assembler, do not use the -N flag (one pass), because there's
  29. * a bug, at least in 5.2a and older, that makes the ENTRY directive not work
  30. * with that option.  It will need a few changes in syntax to work with other
  31. * assemblers.  It might be possible to make versions for other C compilers, so
  32. * I've labeled everything which I know to be Aztec specific with a comment
  33. * containing the word "Aztec".
  34. *
  35. * The one possibly uncool bit of programming used here is that I used
  36. * SysBase->ThisTask instead of FindTask(0), in several places.  If they ever
  37. * make an Amiga that runs tasks on several CPUs at once, that might break.
  38. * This is by Paul Kienitz, 1 December 1991, placed in the public domain.
  39.  
  40.  
  41. ; We avoid pulling in include files with a few definitions here:
  42.  
  43. MEMB_FAST    equ    2        ; exec/memory.i
  44. MEMB_CLEAR    equ    16        ; exec/memory.i
  45. ThisTask    equ    276        ; exec/execbase.i
  46. AttnFlags    equ    296        ; exec/execbase.i
  47. AFB_68881    equ    4        ; exec/execbase.i
  48. AG_OpenLib    equ    $30000        ; exec/alerts.i
  49. AO_DOSLib    equ    $8007        ; exec/alerts.i
  50. pr_ReturnAddr    equ    176        ; libraries/dosextens.i
  51. pr_CLI        equ    172        ; libraries/dosextens.i
  52. pr_MsgPort    equ    92        ; libraries/dosextens.i
  53.  
  54. _LVOTypeOfMem        equ    -534
  55. _LVOAllocMem        equ    -198
  56. _LVOOldOpenLibrary    equ    -408
  57. _LVOAlert        equ    -108
  58. _LVOSupervisor        equ    -30
  59. _LVOFreeMem        equ    -210
  60. _LVOCloseLibrary    equ    -414
  61. _LVOWaitPort        equ    -384
  62. _LVOGetMsg        equ    -372
  63. _LVOReplyMsg        equ    -378
  64. _LVOForbid        equ    -132
  65.  
  66.  
  67. lcall        macro
  68.         jsr    _LVO\1(a6)
  69.         endm
  70.  
  71. AbsExecBase    equ    (4).w
  72.  
  73.         xdef    .begin,_geta4
  74.         xref    __main,_SysBase,_DOSBase
  75.         xref    __savsp                    ; Aztec
  76.         xdef    entry,cleanup        ; for debugging
  77.  
  78. ; the use of the label ".begin" for the entry point is an Aztec-ism
  79.         entry    .begin
  80.  
  81. .begin:
  82. entry:
  83.         far    data                    ; Aztec
  84.         lea    __H1_org+32766,a4    ; to access original globals
  85.  
  86.         lea    __H1_end,a1        ; Aztec; end of initialized data
  87.         lea    __H2_org,a2        ; Aztec; start of BSS
  88.         near    data                    ; Aztec
  89.  
  90.         cmp.l    a1,a2            ; the same address?
  91.         bne    bomb            ; if not, refuse to run
  92.  
  93.         move.l    a0,d6            ; save command arg-line pointer
  94.         move.l    d0,d5            ; save command arg length
  95.  
  96.         lea    __H1_org,a1        ; Aztec; start of data hunk
  97.         move.l    AbsExecBase,a6
  98.         lcall    TypeOfMem        ; what kind of ram is it in?
  99.         bclr.l    #MEMB_FAST,d0        ; do NOT force fast ram!
  100.         bset.l    #MEMB_CLEAR,d0        ; do force cleared memory
  101.  
  102.         move.l    d0,d1            ; memory type requirements
  103.         move.l    #(__H2_end-__H1_org),d0    ; Aztec; size of all globals
  104.         lcall    AllocMem        ; space for a complete copy
  105.         tst.l    d0
  106.         beq    bomb            ; if it failed, don't run
  107.         move.l    d0,a2
  108.  
  109.         lea    __H1_org,a0        ; Aztec; address of old globals
  110.         move.l    a2,a1            ; address of new globals
  111.         move.l    #((__H1_end-__H1_org)/4)-1,d0    ; Aztec; size to copy
  112. copyit:        move.l    (a0)+,(a1)+        ; copy all initialized data
  113.         dbra    d0,copyit
  114.  
  115. * Here's where we get tricky.  We need to put the address of our dublicated
  116. * global variable space someplace where it can be found by geta4(), and we need
  117. * to make sure that we free the copied globals no matter how the program exits.
  118. * What we do is save the pointer on the stack, and then make it appear that the
  119. * final exit address that the program must return to is the address of our
  120. * cleanup routine.  To do this, after pushing the pointer to the copied globals,
  121. * we push the size of the remaining available stack (12 bytes less than the
  122. * original size) and then the address of the cleanup code.  We set the variable
  123. * __savsp to point to that cleanup code address, so that the Aztec exit()
  124. * function will return to that point.  We set the pr_ReturnAddr field of our
  125. * struct Process to point one longword above that, to make the dos.library
  126. * Exit() function return to the cleanup code.  This is also used by geta4() to
  127. * locate the saved pointer to the copied globals.
  128.  
  129.         move.l    a2,-(sp)        ; where geta4() can find it
  130.         move.l    8(sp),a0        ; original size of the stack
  131.         sub.w    #12,a0            ; minus space we're using
  132.         move.l    a0,-(sp)        ; make stack look smaller
  133.         move.l    ThisTask(a6),a0        ; equivalent to FindTask(0)
  134.         move.l    sp,pr_ReturnAddr(a0)    ; for geta4() and dos Exit()
  135.         pea    cleanup            ; so everybody goes there
  136.         move.l    sp,__savsp        ; Aztec; exit() and stack check
  137.  
  138. * The stack now looks like this:
  139. *
  140. *     Stack size in bytes        <-  old pr_ReturnAddr pointed here
  141. *     Return address for final exit    <-  __savsp would have pointed here
  142. *     Pointer to globals for geta4    <-  also used by cleanup
  143. *     New stack size, minus twelve    <-  new pr_ReturnAddr points here
  144. *     Fake return address: cleanup    <-  __savsp will point here
  145. *
  146. * Once __main is called, there will also be these:
  147. *
  148. *     Command line arg address    <-  argument to __main
  149. *     Command line arg length        <-  argument to __main ...SP is now here
  150. *     Return address to this module    <-  falls through to cleanup
  151.  
  152.         bsr    _geta4            ; use new globals
  153.         move.l    a6,_SysBase        ; set up base for C program
  154.         lea    dosname,a1
  155.         lcall    OldOpenLibrary        ; open dos.library
  156.         move.l    d0,_DOSBase        ; set up another base
  157.         bne    dosokay
  158.         move.l    #AG_OpenLib!AO_DOSLib,d7    ; recoverable - no dos
  159.         lea    ThisTask(a6),a5        ; make it show our task adr
  160.         lcall    Alert            ; frighten the user
  161.         bra    bomb            ; and die
  162.  
  163. dosokay:    btst.b    #AFB_68881,AttnFlags+1(a6)    ; is there an FPU?
  164.         beq    nofpu
  165.         lea    resetfpu,a5
  166.         lcall    Supervisor        ; reset it in supervisor mode
  167.  
  168. nofpu:        movem.l    d5/d6,-(sp)        ; pass arguments to _main()
  169.         jsr    __main            ; RUN THE PROGRAM!
  170.         add.w    #12,sp            ; pop extra longword to fake rts
  171.  
  172. cleanup:    move.l    d0,d7            ; set aside the return value
  173.         bsr    _geta4            ; so we can check DOSBase
  174.         move.l    4(sp),a1        ; address of copied globals
  175.         move.l    #(__H2_end-__H1_org),d0    ; size of copied globals
  176.         move.l    AbsExecBase,a6
  177.         lcall    FreeMem            ; get rid of the copy
  178.         addq    #8,sp            ; restore primordial stack
  179.         move.l    ThisTask(a6),a1
  180.         lea    4(sp),a0        ; just to be paranoid...
  181.         move.l    a0,pr_ReturnAddr(a1)    ; restore old pr_ReturnAddr
  182.  
  183.         move.l    _DOSBase,a1
  184.         move.l    a1,d0            ; fake tst.l a1
  185.         beq    dosneveropen        ; was there ever a DOSBase?
  186.         lcall    CloseLibrary        ; if yes, close it
  187.  
  188. dosneveropen:    move.l    d7,d0            ; restore the return value
  189.         rts                ; goodbye cruel world
  190.  
  191.  
  192. bomb:        move.l    AbsExecBase,a6        ; come here if we can't run
  193.         move.l    ThisTask(a6),a0
  194.         tst.l    pr_CLI(a0)        ; are we a Workbench process?
  195.         bne    noworkbench        ; if yes, then we need to
  196.                         ;   reply the startup message:
  197.         lea    pr_MsgPort(a0),a0
  198.         move.l    a0,a3            ; remember our msgport address
  199.         lcall    WaitPort        ; here come de message
  200.         move.l    a3,a0
  201.         lcall    GetMsg            ; got it
  202.         move.l    d0,d3            ; yes, remember it
  203.         lcall    Forbid            ; standard shutdown procedure
  204.         move.l    a3,a1
  205.         lcall    ReplyMsg        ; tell WB to unload us
  206.  
  207. noworkbench:    moveq    #-9,d0            ; the system filters out -1
  208.         rts                ; might return to cleanup
  209.  
  210.  
  211.         mc68881        ; Aztec; activate FPU instruction opcodes
  212.  
  213. resetfpu:    clr.l    -(sp)            ; call this in supervisor mode
  214.         frestore (sp)+            ; reset the FPU
  215.         rte                ; return to user mode
  216.  
  217.  
  218. * Here's our magic routine to set up a4 for accessing the copied globals.
  219. * CALL ONLY FROM WITHIN THE SAME PROCESS.
  220.  
  221. _geta4:        move.l    AbsExecBase,a4
  222.         move.l    ThisTask(a4),a4
  223.         move.l    pr_ReturnAddr(a4),a4    ; ptr to FAKE stack size
  224.         move.l    4(a4),a4        ; stored ptr to copied globals
  225.         lea    32766(a4),a4        ; add the offset
  226.         rts
  227.  
  228. dosname:    dc.b    'dos.library',0        ; for OldOpenLibrary
  229.  
  230.         dseg                ; Aztec
  231. ; Assembler bug:  If you declare __H1_org public within the code segment,
  232. ; then the assembler refers to it with small data even if you have told
  233. ; it to use large data.  Hence the above dseg is necessary.  This does not seem
  234. ; to happen with ordinary symbols, just the __Hx_xxx ones.
  235.         public    __H1_org,__H1_end,__H2_org,__H2_end    ; Aztec
  236.  
  237.     ifd    SHIT
  238. __main:        rts
  239.     dseg
  240. __savsp:    ds.l    1
  241. _SysBase:    ds.l    1
  242. _DOSBase:    ds.l    1
  243.     endc
  244.